<?php
/**
 * STSpam v0.1.1
 * Static spam filter PHP class 
 *
 * Lajos Koszti
 * ajnasz@ajnasz.hu
 * http://ajnasz.hu
 *
 * Usage: check test.php or:
 *********************************
 *
 * $spamCheck = new STSpam();
 * switch($spamCheck->check($_POST['text']))
 * {
 *   case -1:
 *     echo "notspam";
 *     break;
 *   case 0:
 *     echo "probably spam";
 *     break;
 *   case 1:
 *     echo "spam";
 *     break;
 * }
 *
 *********************************
 */


class STSpam {
  var $urlRex = "/https?:\/\/[^\.]+\.(?:\.|[^\/\s\n\b]+)+/i"; // Regular expression for the urls, matches only for the domains
  var $longUrlRex = "/https?:\/\/[^\.]+\.(?:\.|.+)+/i"; // Regular expression for the urls, matches for the whole url
  var $mUrlRex = "/(https?:\/\/[\w\d]+\.(?:\.|[^\/\s\n\b]+)+)/i"; // Store matches
  var $BBnHTMLRex = "/(?:href(?:.|\n)*\[url|\[url(?:.|\n)*href)/i"; // BBcode and html mixed post should be a spam: [url=http://example.org]...<a href="http://example.org">...
  var $whiteChars = "/[áéíóöőúüű]/i"; // White characters. If the comment contains one of these character, the points will be reduced
  /**
   * @constructor
   * @param {Integer} [$criticalURLTime] If the same url is in the post $criticalURLTime * times in the post, it will earn much more point
   * @param {Integer} [$criticalPoint] If the earned point > then criticalPoints the post will be marked as spam
   * @param {Integer} [$probablyPoint] If the earned points > than $probablyPoint but < $criticalPoint, the post is probably a spam, but not sure
   * @param {Integer} [$maxLink] Critical number of links in one post
   * @param {Integer} [$startPoint] The default pont number of the post
   * @param {Integer} [$urlRate] If "not url text strlength"/"original post strlength" <= $urlRate, the text should be a spam
   * @param {Integer} [$criticalLength] If the post is shorter than $criticalLength, the post probably spam
   */
  function STSpam($criticalPoint = 250, $probablyPoint = 150, $ciritcalURLTime = 3, $maxLink = 4, $startPoint = 100, $urlRate = 30, $criticalLength = 10) {
    $this->criticalURLTime = $criticalURLTime;
    $this->criticalPoint = $criticalPoint;
    $this->probablyPoint = $probablyPoint;
    $this->maxLink = $maxLink;
    $this->points = $startPoint;
    $this->urlRate = $urlRate;
    $this->criticalLength = $criticalLength;
    $this->getBlackWords();
  }
  /**
   *The blackWords variable contains many words and regulary expression which will add many points
   */
  function getBlackWords() {
    $this->blackWords = ""
    ."(?:amateur|anal|cam|cartoon|free|live|office)\s*sex|"
    ."(?:amateur|asian|bathroom|beach|naughthy|live|hot) (?:best|cams|sex)|"
    ."(?:bingo|slots) (?:cards|online|odds)|"
    ."(?:bizarre|bondage|cruel|domination|rape|uncensored|spanking|snuff|weird|violent|slave|torture|brutal)\s+comics|"
    ."(?:budget|cashing|credit|new) car|"
    ."(?:caller|cool|download|free|midi|mp3|phone|plyphonic|real|sprint) ringtone|"
    ."(?:car|personal|unsecured) loans?|"
    ."(?:chat|good) girl|"
    ."(?:hentai|homemade|sex|teen) video|"
    ."(?:replice|rolex|) ?watches?|"
    ."bikini(?:.*blogspot|\s*babes)|"
    ."buy (?:soma|cigarette)|"
    ."cool (?:design|disign)|"
    ."free (?:backgammon|keno|pet)|"
    ."generic (?:drugs|pain)|"
    ."hotel (?:atlanta|boston|chicago|houston|washington)|"
    ."mortage (?:broker|insurance|rate)|"
    ."online (?:keno|game|omaha|(?:seven\s*)?card|slots)|"
    ."phe(?:ne?)?termine|"
    ."play (?:bingo|free|slots|keno)|"
    ."sex\s*(?:chat|cams?|date|dating|movies|scene)|"
    ."teen\s*(?:amateur|babes|model|pics?|tit)|"
    ."accutane|aceon|acyclovir|adult|aid appliances|ajcarvelli|albego|alimta|alprazolam|amitriptyline|amoxil|amoxicilin|asphost4free|ass|ativam|"
    ."baccarat|barbital|birthcontrol|blackjack|blog\.lide\.cz\/dmoz|boobs?|breast|busty|butch|butorphano|"
    ."cacalonos|car insurance|carisoprodol|cash advance|cathine|casino|cheap cigarette|cialis|circa\.italyfun|chlordiazepoxide|chromagen|click here|clonazepam|cock|cookware|craps|crib tent|"
    ."delta airline inc|diazepam|dick|didrex|drug|"
    ."effexor|"
    ."fioricet|flexeril|flight uk|flomax|fragrance oil|fuck|"
    ."gang rape|gay|girl cams?|glabster|golfforyouinusa|guitar-strings?|"
    ."hardcore|herpes picture|hold ?em|hoodia|horny|hydrocodone|"
    ."jack|jeep tours|jewelry|jinx\.in\/avandamet|justhello|"
    ."kissing-li-picture-sakura|"
    ."lesbian|levitra|lexatin|lexotan|limpidon|livefriendfinder|loser|"
    ."masturbation|meridia|mlm lead|money investment|mp3 canzoni|muscular skeletal|mycoolitaly|"
    ."nexium|norvasc|nude|"
    ."pantie|paxil|paxor|payday|penis|pharmacy?|piss|plavix|plexonal|poker|poquerlinea|porn|prednisone|prevacid|pussy|"
    ."queroumforum|"
    ."rape|registrazione|replica handbags|richly scented|ringtones?|rolex|roulette|"
    ."satellite|ses-search|sexdreams|slot machine|sperm|sport-bet|sspkts13|stadol|"
    ."thedeluxefree|tenormin|tit|torbutrol|tramadol|two-top|"
    ."ultram|uzhgorod|"
    ."valium|vantin|vauxhall|veronal|viagra|vicodin|videochat|violetpots|"
    ."webcams?|weight watcher|worldartnames|"
    ."xanical|xanax|"
    ."yahoo bingo|yandex";

    $blogspots = '(?:erotic-adventure|musicadownload)\.blogspot\.com';
    $myblogvoice = '(testo|registrazione)\.myblogvoice\.com';
    $infos = '(?:[a-z]+\.dzca|i-cars|abbigliamento\.theitaly|clcikhere|creaeb|itggc|parkblog|wapfuns|x-comp)\.info';
    $nets = '(?:hostwq|s-url|spamim|ulan-knv)\.net|';
    $coms = '(?:8888mb|bestmedsite|charresult|faststartdirect|fm7\.biz|freehostia|imlive|jamiep|medved|my-investment|rollyo|rubyurl|scrubsystem|thelotter)\.com';
    $orgs = '(?:leadf-it|livingeconomies|news\.kavinet\.org)\.org';


    $this->blackURLS = 'awardspace\.biz|italyworld\.cc|mail\.ru|mixfreaks\.nl|tram\.adol\.sblog\.cz|tikva\.asp2\.cz|urlin\.it|ksiegi\.emix\.net\.pl|symy\.jp|';
    $blogspots = trim($blogspots);
    if(!empty($blogspots)) {
      $this->blackURLS .= '|' . $blogspots;
    }
    $myblogvoice = trim($myblogvoice);
    if(!empty($myblogvoice)) {
      $this->blackURLS .= '|' . $myblogvoice;
    }
    $infos = trim($infos);
    if(!empty($infos)) {
      $this->blackURLS .= '|' . $infos;
    }
    $nets = trim($nets);
    if(!empty($infos)) {
      $this->blackURLS .= '|' . $nets;
    }
    $orgs = trim($orgs);
    if(!empty($infos)) {
      $this->blackURLS .= '|' . $orgs;
    }
    $coms = trim($coms);
    if(!empty($infos)) {
      $this->blackURLS .= '|' . $coms;
    }
  }
  /**
   * @param {String} $text testable string
   * @return {Integer} 1 = Spam, 0 = maybe spam, -1 = not spam
   */
  function check($text) {
    $this->text = trim($text);
    $this->polling();
    if($this->points >= $this->criticalPoint) {
      return 1;
    } elseif($this->points >= $this->probablyPoint) {
      return 0;
    } else {
      return -1;
    }
  }
  /**
   * Tester function, which runs the tests, pass the points
   */
  function polling() {
    if($this->checkWhiteChars()) {
      $this->points -= 20;
    }
    if($this->checkBBCodeHTML()) {
      $this->points += $this->criticalPoint;
    }
    if($this->tooShort()) {
      $this->points += 20;
    }
    if($this->containsURL()) {
      $urlTimes = $this->timesURL();
      $maxcounter  = 0;
      foreach($urlTimes as $time) {
        $maxcounter += $time;
        if($time >= $this->criticalURLTime) {
          $this->points += $time*35;
        } else {
          $this->points += $time*5;
        }
      }
      if($maxcounter > $this->maxLink) {
        $this->points += $maxcounter*35;
      }
      if($this->onlyURL()) {
        $this->points += 20;
      }
    }
    if($this->checkSpamExpression() || $this->checkSpamURL()) {
      $this->points += $this->criticalPoint;
    }
  }
  /**
   * Check for the whitechars in the message, because the spammer doesn't use national characters
   * @return {Boolean}
   */
  function checkWhiteChars() {
    return preg_match($this->whiteChars, $this->text);
  }
  /**
   * Check BB Code and HTML links together, I'm sure, this is spam
   * @return {Boolean}
   */
  function checkBBCodeHTML() {
    return preg_match($this->BBnHTMLRex, $this->text);
  }
  /**
   * Is the comment contains any url?
   * @return {Boolean}
   */
  function containsURL() {
    return preg_match($this->urlRex, $this->text);
  }
  /**
   * Check, that an url how many times is in a singel post
   * @return {Integer}
   */
  function timesURL() {
    $urlTimer = array();
    preg_match_all($this->mUrlRex, $this->text, $matches);
    foreach($matches[0] as $match) {
      if(!$urlTimer[$match]) {
        $urlTimer[$match] = 0;
      }
      $urlTimer[$match]++;
    }
    return $urlTimer;
  }
  /**
   * Check for spam words
   * @return {Boolean}
   */
  function checkSpamExpression() {
    return preg_match('/\b(?:' . $this->blackWords . ')\b/i', $this->text);
  }
  /**
   * Check for black urls
   * @return {Boolean}
   */
  function checkSpamURL() {
    return preg_match('/(?:ht|f)tps?:\/\/(?:' . $this->blackURLS . ')/i', $this->text);
  }
  /**
   * Check the post length
   * @return {Boolean}
   */
  function tooShort() {
    return (count($this->text) < $this->criticalLength);
  }
  /**
   * Check for the url:not url content rate
   * return {Boolean}
   */
  function onlyURL() {
    $str = preg_replace($this->longUrlRex, '', $this->text);
    return (strlen($str) / strlen($this->text) < $this->urlRate);
  }
}
?>
